#include "SimEEG_device.h"
#include "ColorfulLog.h"

#include <armadillo>
SimEEG_device::SimEEG_device(QObject *parent, const char* serverIP, int serverPort)
    :CollectBase(parent)
{
	memset(&serverSock, 0, sizeof(serverSock));
    serverSock.sin_family = AF_INET;
    serverSock.sin_port = htons(serverPort);
    serverSock.sin_addr.s_addr = inet_addr(serverIP);
}

SimEEG_device::~SimEEG_device()
{
    close(clientSockFd);
}


void SimEEG_device::run(){
    dataCollecting();
}

int SimEEG_device::dataCollecting(void* args){
    // 创建一个TCP客户端
    clientSockFd = socket(AF_INET, SOCK_STREAM, 0);
    if(clientSockFd == -1){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
    }

    while(!is_connecting()){
        // 由于使用子进程唤醒虚拟服务器,需要等待服务器启动
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        int res = ::connect(clientSockFd, (struct sockaddr*)&serverSock, sizeof(serverSock));
        // int res = -1;
        if( res < 0){
            static int counts = 0;
            ++counts;
            printf("connect error: %s(errno: %d)..........retry:%d\n",strerror(errno),errno,counts);
            #if 1
            std::this_thread::sleep_for(std::chrono::milliseconds(800));
            #else
            QEventLoop loop;//定义一个新的事件循环
            QTimer::singleShot(800, &loop, SLOT(quit()));//创建单次定时器，槽函数为事件循环的退出函数
            loop.exec();//事件循环开始执行，程序会卡在这里，直到定时时间到，本循环被退出
            #endif

            // 重连8次,超时结束脑电采集线程
            if(counts >= 8){
                collectingEEG(false);
                printf_red("=== simServer connecting timeout... ===\n");
                counts = 0;
                return -1;
            }
            counts = 0;
        }
        else{
            // is_connected = true;
            changeConnectingState(true);
            const char *server_ip = inet_ntoa(serverSock.sin_addr);
            uint16_t server_port = ntohs(serverSock.sin_port);
            printf_green("服务端:[%s:%d]已连接....\n",server_ip,server_port);
            printf(NONE);
        }
    }
    
    // 采集线程主循环
    printf_yellow("SimEEG_device::dataCollecting...\n");
    while (is_collecting())
    {
        // // 从TCP协议中读取数据并解析
        ssize_t readLen = read(clientSockFd, buffer, sizeof(buffer));
        ssize_t cubeLen = readLen / SIM_CHANNEL_COUNT / 4;
        if(readLen == 0){
            printf("sim server disconnected.\n");
            return 0;
        }
        if(cubeLen == 0){
            printf("readLen:%ld\n",readLen);
            printf("data error !!!\n");
            return -1;
        }

        float *rec_buff_ptr = reinterpret_cast<float*>(buffer);
        #ifdef DEBUG
        for(int i=0; i<63; ++i){
            std::cout << "data[" << i << "]:" << *org_fdata << std::endl;
            ++org_fdata;
        }
        #endif
        // 初始化org_data, false表示不释放rec_buff_ptr数组
        arma::fmat org_data(rec_buff_ptr, SIM_CHANNEL_COUNT, 1, cubeLen, false);
        // printf("simeeg:org_data:%lld*%lld\n",org_data.n_rows, org_data.n_cols);
        QVariant sendData;

        sendData.setValue(arma::conv_to<arma::mat>::from(org_data));
        // 发送
        emit send_ClientData(sendData);

    }
    changeConnectingState(false);
    close(clientSockFd);
    printf("simeeg_device stop collecting.\n");
    return 0;
}

// void SimEEG_device::collectingEEG(bool state){
//     is_collecting = state;
// }

// bool SimEEG_device::iscollecting(){
//     return is_collecting;
// }
const QMap<int,QString>& SimEEG_device::getElectrodeMap(){
    static QMap<int, QString> electrodeMap;
    if(!electrodeMap.isEmpty())
        return electrodeMap;

    using namespace SIM_EEGDEV;
    electrodeMap = QMap<int, QString>({
        {FP1, "FP1"},
        {FPZ, "FPZ"},
        {FP2, "FP2"},
        {F7, "F7"},
        {F3, "F3"},
        {FZ, "FZ"},
        {F4, "F4"},
        {F8, "F8"},
	    {FC5, "FC5"},
        {FC1, "FC1"},
        {FC2, "FC2"},
        {FC6, "FC6"},
        {M1, "M1"},
        {T7, "T7"},
        {C3, "C3"},
        {CZ, "CZ"},
	    {C4, "C4"},
        {T8, "T8"},
        {M2, "M2"},
        {CP5, "CP5"},
        {CP1, "CP1"},
        {CP2, "CP2"},
        {CP6, "CP6"},
        {P7, "P7"},
	    {P3, "P3"},
        {PZ, "PZ"},
        {P4, "P4"},
        {P8, "P8"},
        {POZ, "POZ"},
        {O1, "O1"},
        {O2, "O2"},
        // {EOG, "EOG"},
	    {AF7, "AF7"},
        {AF3, "AF3"},
        {AF4, "AF4"},
        {AF8, "AF8"},
        {F5, "F5"},
        {F1, "F1"},
        {F2, "F2"},
        {F6, "F6"},
	    {FC3, "FC3"},
        {FCZ, "FCZ"},
        {FC4, "FC4"},
        {C5, "C5"},
        {C1, "C1"},
        {C2, "C2"},
        {C6, "C6"},
        {CP3, "CP3"},
	    {CP4, "CP4"},
        {P5, "P5"},
        {P1, "P1"},
        {P2, "P2"},
        {P6, "P6"},
        {PO5, "PO5"},
        {PO3, "PO3"},
        {PO4, "PO4"},
	    {PO6, "PO6"},
        {FT7, "FT7"},
        {FT8, "FT8"},
        {TP7, "TP7"},
        {TP8, "TP8"},
        {PO7, "PO7"},
        {PO8, "PO8"},
        {OZ, "OZ"}
    });
    return electrodeMap;
}

